package com.zyw.auth.shiro.realm;

import com.zyw.auth.common.IConstants;
import com.zyw.auth.domain.Administrator;
import com.zyw.auth.domain.Rights;
import com.zyw.auth.shiro.service.AdministratorRealmService;
import org.apache.commons.lang.StringUtils;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.AuthenticationInfo;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authc.LockedAccountException;
import org.apache.shiro.authc.SimpleAuthenticationInfo;
import org.apache.shiro.authc.UnknownAccountException;
import org.apache.shiro.authc.credential.CredentialsMatcher;
import org.apache.shiro.authc.credential.HashedCredentialsMatcher;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.crypto.hash.Md5Hash;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
import org.apache.shiro.util.ByteSource;
import org.apache.shiro.util.CollectionUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.util.Collection;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Set;

@Component("lxbAdminRealm")
public class LxbAdminRealm extends AuthorizingRealm {
	@Autowired
	private AdministratorRealmService adminService;

	public LxbAdminRealm() {
		// 默认采用MD5散列加密算法
		HashedCredentialsMatcher credentialsMatcher = new HashedCredentialsMatcher(Md5Hash.ALGORITHM_NAME);
		this.setCredentialsMatcher(credentialsMatcher);
	}
	
	public LxbAdminRealm(CredentialsMatcher credentialsMatcher) {
		// 后续优化登录认证，比如：输入错误几次锁住1小时等，可以扩展HashedCredentialsMatcher去实现
		// ，并指定凭据匹配器，做为构造函数入参，即可。
		this.setCredentialsMatcher(credentialsMatcher);
	}
	
	/**
	 * 身份认证/登录
	 */
	@Override
	protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
		if (token.getPrincipal() == null) {
			throw new UnknownAccountException();
		}
		String userName = (String) token.getPrincipal();
		Administrator admin = null;
		try {
			admin = this.adminService.findByUserName(userName);
		} catch (Exception ex) {
			throw new AuthenticationException(ex);
		}
		if (admin == null) {
			// 用户名错误
			throw new UnknownAccountException();
		}
		if (IConstants.USER_STATUS_FORBIDDEN.equals(admin.getUserStatus())) {
			// 用户禁用
			throw new LockedAccountException();
		}
		SimpleAuthenticationInfo authInfo = new SimpleAuthenticationInfo(admin, admin.getPassword(), getName());
		authInfo.setCredentialsSalt(ByteSource.Util.bytes(admin.getPasswordSalt()));
		return authInfo;
	}

	/**
	 * 授权
	 */
	@SuppressWarnings("unchecked")
	@Override
	protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
		SimpleAuthorizationInfo authorizationInfo = new SimpleAuthorizationInfo();
		// 根据当前 realm认证通过身份，获取授权（防止多realm交叉问题））
		Collection<Administrator> adminPrincipals = principals.fromRealm(getName());
		if (!CollectionUtils.isEmpty(adminPrincipals)) {
			Administrator admin = adminPrincipals.iterator().next();
			List<Rights> rightsList = this.adminService.queryRights(admin.getAdminId());
            if (!CollectionUtils.isEmpty(rightsList)) {
                // 遍历权限，进行授权
                Set<String> permissions = new LinkedHashSet<String>();
                rightsList.stream().filter(right -> StringUtils.isNotBlank(right.getPermissions()))
                        .forEach(right -> permissions.add(right.getPermissions()));
                authorizationInfo.setStringPermissions(permissions);
            }
		}
		
		return authorizationInfo;
	}
	
	/**
	 * 清空指定用户授权缓存
	 */
	public void clearCachedAuthorizationInfo(PrincipalCollection principals) {
		super.clearCachedAuthorizationInfo(principals);
	}

	/**
	 * 清空所有用户授权缓存
	 */
	public void clearAllCachedAuthorizationInfo() {
		getAuthorizationCache().clear();
	}
	
}
